package com.hmdp.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.Voucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisWorker;
import com.hmdp.utils.UserHolder;
import javafx.scene.input.DataFormat;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    @Resource
    ISeckillVoucherService iSeckillVoucherService;

    @Resource
    RedisWorker redisWorker;
    @Override
    public Result seckillVoucher(Long voucherId) {
        //查询优惠劵
        SeckillVoucher coupons = iSeckillVoucherService.getById(voucherId);
        //VoucherOrder Coupons = getById(voucherId);
        if(ObjectUtil.isEmpty(coupons)){
            return Result.fail("优惠劵"+voucherId+"不存在");
        }
        //判断秒杀是否开始
        if(coupons.getBeginTime().isAfter(LocalDateTime.now())){
            return Result.fail("优惠时间还没开始，请在"+coupons.getBeginTime().format(DateTimeFormatter.ofPattern("yyyy:MM:dd"))+"使用");
        }
        //判断秒杀是否结束
        if(coupons.getEndTime().isBefore(LocalDateTime.now())){
            return Result.fail("优惠劵已过期，请在有效期内使用。过期时间为"+coupons.getEndTime().format(DateTimeFormatter.ofPattern("yyyy:MM:dd")));
        }
        //判断库存是否充足
        if(coupons.getStock() < 1){
            return Result.fail("优惠劵已售空");
        }
        Long userId = UserHolder.getUser().getId();
        //这里给每个用户加锁，锁住用户id,一个用户只能拿一把锁，不同用户不会互相干扰
        //普通的toString()方法最后都在堆中new一个新字符串，这样不同对象是锁不住的。
        //使用intern()方法：如果常量池中有这个字符串就不会new，而是直接返回常量池中的地址
        synchronized (userId.toString().intern()){
            //这里通过this调用是用不了事务的，spring的事务是通过代理类实现，我们要拿到它的代理类再调用
            //需要把代理类暴露@EnableAspectJAutoProxy(exposeProxy = true)。并且引入aspectj的依赖
            IVoucherOrderService proxy = (IVoucherOrderService)AopContext.currentProxy();
            return proxy.createVocherOrder(voucherId);
        }
    }

    /**
     * 根据优惠劵创建订单，这个方法操作优惠劵表和订单表，要加事务
     * @param voucherId 优惠劵id
     * @return 订单id
     */
    @Transactional
    public Result createVocherOrder(Long voucherId) {
        //判断用户是否一人一单
        Long userId = UserHolder.getUser().getId();
        int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
        if(count>0){
            return Result.fail("一人只能下一单");
        }
        //删减库存,乐观锁stock > 0
        boolean isUpdate = iSeckillVoucherService.update().setSql("stock = stock -1").eq("voucher_id", voucherId).gt("stock",0).update();
        if(!isUpdate){
            return Result.fail("优惠劵已售空");
        }
        //创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        //订单id
        long orderId = redisWorker.getUnitId("order");
        voucherOrder.setId(orderId);
        //优惠劵id
        voucherOrder.setVoucherId(voucherId);
        //用户id
        voucherOrder.setUserId(UserHolder.getUser().getId());
        //存入数据库
        save(voucherOrder);
        //返回订单id
        return Result.ok(orderId);
    }
}
